package com.ruoyi.good.repository;

import com.ruoyi.common.constant.Constants;
import com.ruoyi.good.event.GoodSkuStockZeroMessageEvent;
import com.ruoyi.good.model.entity.GoodSkuEntity;
import com.ruoyi.good.model.vo.GoodSkuStockKeyVO;
import com.ruoyi.good.persistent.dao.IGoodSkuDao;
import com.ruoyi.good.persistent.po.GoodSku;
import com.ruoyi.good.persistent.redis.IRedisService;
import com.ruoyi.trigger.publish.EventPublisher;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * TODO
 *
 * @Description
 * @Author wkm
 * @Date 2024/12/29
 **/
@Repository
@Slf4j
public class ActivityRepository implements IActivityRepository{

    @Resource
    private IRedisService redisService;
    @Resource
    private EventPublisher eventPublisher;
    @Resource
    private IGoodSkuDao goodSkuDao;
    @Resource
    private GoodSkuStockZeroMessageEvent goodSkuStockZeroMessageEvent;

    @Override
    public GoodSkuEntity queryGoodSku(Long goodsId) {
        GoodSku goodSku = goodSkuDao.queryGoodSku(goodsId);
        String cacheKey = Constants.RedisKey.ACTIVITY_SKU_STOCK_COUNT_KEY + goodsId;
        Long cacheSkuStock = redisService.getAtomicLong(cacheKey);
        if(null == cacheSkuStock || 0 == cacheSkuStock){
            cacheSkuStock = 0L;
        }
        return GoodSkuEntity.builder()
                .goodsId(goodSku.getGoodsId())
                .stockCount(goodSku.getStockCount())
                .stockCountSurplus(goodSku.getStockCountSurplus())
                .build();
    }

    @Override
    public void goodSkuStockConsumeSendQueue(GoodSkuStockKeyVO goodSkuStockKeyVO) {
        String cacheKey = Constants.RedisKey.ACTIVITY_SKU_COUNT_QUERY_KEY;
        RBlockingQueue<GoodSkuStockKeyVO> blockingQueue = redisService.getBlockingQueue(cacheKey);
        RDelayedQueue<GoodSkuStockKeyVO> delayedQueue = redisService.getDelayedQueue(blockingQueue);
        delayedQueue.offer(goodSkuStockKeyVO, 3, TimeUnit.SECONDS);
    }


    @Override
    public void cacheGoodSkuStockCount(String cacheKey, Integer stockCount) {
        if(redisService.isExists(cacheKey)) return;
        redisService.setAtomicLong(cacheKey,stockCount);
    }


    @Override
    public boolean subtractionGoodSkuStock(Long goodsId, String cacheKey, Date endDateTime) {
        long surplus = redisService.decr(cacheKey);
        goodSkuDao.updateGoodSkuStock(goodsId);
        GoodSku goodSku = goodSkuDao.queryGoodSku(goodsId);
        Long sub = Long.valueOf(goodSku.getStockCountSurplus());
        if(sub == 0){
            /** 库存 = 0 */
            eventPublisher.publish(goodSkuStockZeroMessageEvent.topic(),goodSkuStockZeroMessageEvent.buildEventMessage(goodsId));
            return false;
        } else if (surplus < 0) {
            redisService.setAtomicLong(cacheKey,0);
            return false;
        }

        String lockKey = cacheKey + Constants.UNDERLINE + surplus;
        long expireMillis = endDateTime.getTime() - System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1);
        Boolean lock = redisService.setNx(lockKey,expireMillis,TimeUnit.MILLISECONDS);
        if(!lock){
            log.info("商品库存加锁失败 {}",lockKey);
        }
        return lock;
    }


    @Override
    public GoodSkuStockKeyVO takeQueueValue() {
        String cacheKey = Constants.RedisKey.ACTIVITY_SKU_COUNT_QUERY_KEY;
        RBlockingQueue<GoodSkuStockKeyVO> destinationQueue = redisService.getBlockingQueue(cacheKey);
        return destinationQueue.poll();
    }

    @Override
    public void clearQueueValue() {
        String cacheKey = Constants.RedisKey.ACTIVITY_SKU_COUNT_QUERY_KEY;
        RBlockingQueue<GoodSkuStockKeyVO> destinationQueue = redisService.getBlockingQueue(cacheKey);
        destinationQueue.clear();
    }

    @Override
    public void updateGoodSkuStock(Long goodsId) {
        goodSkuDao.updateGoodSkuStock(goodsId);
    }

    @Override
    public void clearGoodSkuStock(Long goodsId) {
        goodSkuDao.clearGoodSkuStock(goodsId);
    }
}
